package mr.go.set;

import java.util.Set;

import mr.go.set.samples.Counter;

/**
 * Aggregator is used in conjunction with {@link AggregatedSet}. It defines type
 * able to give values to some unknown elements using "fold-like" operation:
 * instance of this type determines the first, inital value, and then computes
 * every other value using existing one and new one. See {@link Counter} for
 * example of counting aggregator. Another interesting example may be mean
 * aggregator which would produce values representing mean value of some
 * quantity (eg. time):
 * 
 * 
 * <pre>
 * 
 * public final class MeanTime {
 * 
 * 	private int averageTime;
 * 
 * 	private int count;
 * 
 * 	public MeanTime() {
 * 	}
 * 
 * 	public MeanTime(int count, int averageTime) {
 * 		this.count = count;
 * 		this.averageTime = averageTime;
 * 	}
 * 
 * 	public int getAverageTime() {
 * 		return averageTime;
 * 	}
 * 
 * 	public int getCount() {
 * 		return count;
 * 	}
 * }
 * </pre>
 * 
 * Given this class definition we might define mean aggregator
 * 
 * <pre>
 * 
 * public class MeanAggregator implements Aggregator&lt;MeanTime&gt; {
 * 
 * 	&#064;Override
 * 	public MeanTime aggregate(MeanTime value, MeanTime current) {
 * 		int n = current.getCount();
 * 		int e = current.getAverageTime();
 * 		int n1 = n + 1;
 * 		return new MeanTime(n1, ((value.getAverageTime() + n * e) / n1));
 * 	}
 * 
 * 	&#064;Override
 * 	public MeanTime initial() {
 * 		return new MeanTime();
 * 	}
 * 
 * }
 * </pre>
 * 
 * @author Marcin Rzeźnicki
 * 
 * @param <P>
 *            type of values produced by <tt>aggregator</tt>
 */
public interface Aggregator<P> {

	/**
	 * Produces next value of some element from given values. Implementation
	 * should be prepared for null {@code value} - {@link AggregatedSet} passes
	 * null when element is added to set using standard {@link Set} calls (apart
	 * from this - it is perfectly possible for caller to pass null).
	 * <p>
	 * IMPORTANT: implementation should <b>always</b> return new instance of P.
	 * If it does not there is risk of deadlock. See implementation of
	 * {@link AggregatedSet#atomicUpdate(mr.go.set.AggregatedSet.Value, Object)}
	 * </p>
	 * 
	 * @param value
	 *            new value
	 * @param current
	 *            current value
	 * @return next value
	 */
	P aggregate(P value, P current);

	/**
	 * Produces inital value
	 * 
	 * @return initial value
	 */
	P initial();
}
